/*  Copyright © 2009 Blake Hegerle -*- C++ -*- */

/*  This file is part of metal.
 
    Metal is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see
    <http://www.gnu.org/licenses/>.

*/

#pragma once

#include "../util.h"

namespace metal {
  namespace meta {
    template<typename I, typename T>
    struct binding {
      typedef I ident;
      typedef T type;
    };

    template<typename... B>
    struct bindings { };

    template<typename I, typename T, typename B>
    struct bind;

    template<typename I, typename T, typename... B>
    struct bind<I, T, bindings<B...>> {
      typedef bindings<binding<I, T>, B...> type;
    };

    template<typename I, typename... B>
    struct get;

    template<typename I>
    struct get<I, bindings<>> {
      static const bool is_bound = false;
      typedef void type;
    };

    template<typename I, typename J, typename T, typename... B>
    struct get<I, bindings<binding<J, T>, B...>> {
      typedef get<I, bindings<B...>> next;

      static const bool is_bound = next::is_bound;
      typedef typename next::type type;
    };

    template<typename I, typename T, typename... B>
    struct get<I, bindings<binding<I, T>, B...>> {
      static const bool is_bound = true;
      typedef T type;
    };
    
    template<typename B0, typename B1>
    struct concat_bindings;
    
    template<typename... Args0, typename... Args1>
    struct concat_bindings<bindings<Args0...>, bindings<Args1...> > {
      typedef bindings<Args0..., Args1...> type;
    };
  }

  template<typename... Bindings>
  struct count<meta::bindings<Bindings...> > {
    static const unsigned int value = count<Bindings...>::value;
  };
}
